package com.kele.search.service;

import com.kele.common.model.response.PageResult;
import com.kele.model.goods.SearchGoods;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class SearchService {

    @Autowired
    RestHighLevelClient restHighLevelClient;

    /**
     * GET kele_goods/_search
     * {
     *   "query": {
     *     "bool": {
     *       "must": [
     *        {
     *          "match": {
     *            "title": "手机"
     *          }
     *        }],
     *        "filter": [
     *          {"range": {
     *            "price": {
     *              "gte": 1500,
     *              "lte": 2000
     *            }
     *          }}
     *        ]
     *     }
     *   },
     *   "from": 0,
     *   "size": 10,
     *   "sort": [
     *     {
     *       "price": {
     *         "order": "desc"
     *       }
     *     }
     *   ],
     *   "highlight": {
     *     "pre_tags": ["<strong style='color:red'>"],
     *     "post_tags": ["</strong>"],
     *     "fields": {
     *       "title": {}
     *     }
     *   }
     * }
     * @param pageNo
     * @param pageSize
     * @param searchMap
    {
        "title":"华为",
        "minPrice":1000,
        "maxPrice":2000,
        "sort":"desc"
    }
     * @return
     * @throws IOException
     * @throws ParseException
     */
    public Map<String,Object> search(Integer pageNo, Integer pageSize, Map searchMap)
            throws IOException, ParseException {

        Map<String,Object> map = new HashMap<>();
        //1 SearchRequset  GET kele_goods/_search
        SearchRequest searchRequest = new SearchRequest("kele_goods");
        //{}
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        String title = (String)searchMap.get("title");
        if(!StringUtils.isEmpty(title)) {
            QueryBuilder queryBuilder = QueryBuilders.matchQuery("title", title);
            boolQueryBuilder.must(queryBuilder);//query--->bool -->must
        }
        RangeQueryBuilder rangeQueryBuilder = new RangeQueryBuilder("price");
        rangeQueryBuilder.gte(searchMap.get("minPrice"));
        rangeQueryBuilder.lte(searchMap.get("maxPrice"));

        boolQueryBuilder.filter(rangeQueryBuilder);//query-->bool -->filter -->range
        String category = (String)searchMap.get("category");
        if(!StringUtils.isEmpty(category)){
            MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder("category",category);
            boolQueryBuilder.filter(matchQueryBuilder);//query-->bool -->filter -->match
        }

        searchSourceBuilder.query(boolQueryBuilder);//query-->bool

        searchSourceBuilder.from((pageNo-1)*pageSize);//from
        searchSourceBuilder.size(pageSize);//size
        //排序
        SortOrder sortOrder = SortOrder.ASC;
        String sort_order = (String)searchMap.get("sort");
        if(!StringUtils.isEmpty(sort_order)){
            if(sort_order.equals("desc")){
                sortOrder = SortOrder.DESC;
            }
        }
        searchSourceBuilder.sort("price",sortOrder);//sort
        HighlightBuilder highlightBuilder = new HighlightBuilder().field("title");
        highlightBuilder.preTags("<strong style='color:red'>");
        highlightBuilder.postTags("</strong>");
        searchSourceBuilder.highlighter(highlightBuilder);//hightlight

        //聚合查询
        AggregationBuilder aggregationBuilder = AggregationBuilders
                .terms("category_1905A")
                .field("category");
        searchSourceBuilder.aggregation(aggregationBuilder);

        searchRequest.source(searchSourceBuilder);

        SearchResponse searchRes = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        //获取聚合查询的结果
        List<String> categoryList = new ArrayList<>();

        Aggregations aggregations = searchRes.getAggregations();
        ParsedStringTerms category_1905A = aggregations.get("category_1905A");
        List<? extends Terms.Bucket> buckets = category_1905A.getBuckets();

        for (Terms.Bucket bucket : buckets) {
            System.out.println(bucket.getKey() + "-->" + bucket.getDocCount());
            categoryList.add((String)bucket.getKey());
        }
        map.put("categoryList",categoryList);

        SearchHits hits = searchRes.getHits();
        Long total = hits.getTotalHits().value;
        SearchHit[] hitsArray = hits.getHits();

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<SearchGoods> records = new ArrayList<>();
        for (SearchHit documentFields : hitsArray) {
            Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();
            SearchGoods searchGoods = new SearchGoods();
            searchGoods.setGoodsId((Long)sourceAsMap.get("goodsid"));
            searchGoods.setTitle((String)sourceAsMap.get("title"));
            searchGoods.setBrand((String)sourceAsMap.get("brand"));
            searchGoods.setPrice(new BigDecimal(sourceAsMap.get("price").toString()));
            searchGoods.setMainPic((String)sourceAsMap.get("main_pic"));
            if(!StringUtils.isEmpty((String)sourceAsMap.get("updatetime"))){
                searchGoods.setUpdateTime(simpleDateFormat.parse((String)sourceAsMap.get("updatetime")));
            }
            Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();
            HighlightField highlightField = highlightFields.get("title");
            if(highlightField!=null){
                Text[] fragments = highlightField.getFragments();
                if(fragments!=null && fragments.length>0){
                    System.out.println(fragments[0]);
                    searchGoods.setTitle(fragments[0].string());
                }
            }
            records.add(searchGoods);
        }

        map.put("goodsList",new PageResult<>(total,records));
        return map;
    }
}
